#include "systeminit.h"
#include <driver/gpio.h>
#include <nvs_flash.h>
#include <esp_console.h>
#include <esp_spiffs.h>
#include "pin_map.h"


#include "console_proc.h"
#include "cmd_nvs.h"
#include "cmd_system.h"
#include "console_cli_proc.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "driver/dac_oneshot.h"
#include "wifi_proc.h"
#define TAG     "system_init"

LED_Device led_device;
MeasDevice meas_device;
DriversMotor driver_a, driver_b;
Encoder_Base encoder_device;
Encoder_MT6701 encoder_mt6701_dev;
void eps_sysinit(void)
{
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    esp_vfs_spiffs_conf_t conf = {
        .base_path = "/spiffs",
        .partition_label = NULL,
        .max_files = 5,
        .format_if_mount_failed = true,
    };
    ret = esp_vfs_spiffs_register(&conf);
    if (ret != ESP_OK) {
        if (ret == ESP_FAIL) {
            ESP_LOGE(TAG, "Failed to mount or format filesystem");
        } else if (ret == ESP_ERR_NOT_FOUND) {
            ESP_LOGE(TAG, "Failed to find SPIFFS partition");
        } else {
            ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
        }
    }

    size_t total = 0, used = 0;
    ret = esp_spiffs_info(NULL, &total, &used);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret));
    } else {
        ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
    }

}

void led_init(void)
{
    led_device.register_pin(LED_PIN, 1);
    led_device.upadte_pin(LED_PIN, LED_MODE_HEARTBEATE, 100, 50);
    led_device.run();
}

void meas_device_init(void)
{
    meas_device.init(ADC_CH_VBUS_VOLT, ADC_CH_MT_OUT, ADC_CH_NTC_TEMP);
}


void driver_motor_init(void)
{
    driver_a.init(A_PHASE_IN1_PIN, A_PHASE_IN2_PIN, A_PHASE_VREF_DAC_PIN);
    driver_b.init(B_PHASE_IN1_PIN, B_PHASE_IN2_PIN, B_PHASE_VREF_DAC_PIN);
}


void console_proc_init(void)
{
    console_init();
    esp_console_register_help_command();
    register_system();
    register_nvs();
    register_device_control();
    console_run();

}

void encoder_device_init(void)
{
    // encoder_device.init(23, 18);
    // encoder_device.run(false);
    encoder_mt6701_dev.init(SPI3_HOST, 18, 19, 5);
    uint16_t angle = encoder_mt6701_dev.raw_code_read();
    ESP_LOGI(TAG, "MT6701 init angle [%d]", angle);
}

void user_pin_init(void)
{
    gpio_set_direction((gpio_num_t)21, GPIO_MODE_OUTPUT);
    gpio_set_direction((gpio_num_t)22, GPIO_MODE_OUTPUT);
    gpio_set_direction((gpio_num_t)9, GPIO_MODE_OUTPUT);
    gpio_set_direction((gpio_num_t)10, GPIO_MODE_OUTPUT);
    gpio_set_level((gpio_num_t)21, 0);
    gpio_set_level((gpio_num_t)22, 0);
    gpio_set_level((gpio_num_t)9, 0);
    gpio_set_level((gpio_num_t)10, 0);
}


void system_init(void)
{
    eps_sysinit();
    led_init();
    // wifi_proc_init();
    // user_pin_init();
    meas_device_init();
    driver_motor_init();
    // wifi_init_softap();
    console_proc_init();
    // httpserver_run();
    encoder_device_init();
}


MeasDevice & meas_device_get(void)
{
    return meas_device;
}

LED_Device & led_device_get(void)
{
    return led_device;
}

Encoder_MT6701 & encoder_device_get(void)
{
    return encoder_mt6701_dev;
}


DriversMotor & motor_driver_get(uint8_t ch)
{
    return ch == 0 ? driver_a : driver_b;
}
